home *** CD-ROM | disk | FTP | other *** search
/ Software Vault: The Gold Collection / Software Vault - The Gold Collection (American Databankers) (1993).ISO / cdr25 / pmenv.zip / PMENV.C < prev    next >
C/C++ Source or Header  |  1993-03-01  |  18KB  |  615 lines

  1.  
  2. /*
  3.  *  PMEnv
  4.  *
  5.  *  OS/2 Presentation Manager Envelope Printing Program
  6.  *  Version 1.1
  7.  *
  8.  *  Dave Briccetti & Associates         CompuServe: 74475,1072
  9.  *  P.O. Box 1713
  10.  *  Lafayette, CA  94549-7013
  11.  *  USA
  12.  *
  13.  *  Copyright (c) 1990, David C. Briccetti
  14.  *  All rights reserved.
  15.  *
  16.  *  See the extended help when running the program for more information.
  17.  */
  18.  
  19. #include <io.h>
  20. #include <malloc.h>
  21. #include <process.h>
  22. #include <stddef.h>
  23. #include <stdio.h>
  24. #include <stdlib.h>
  25. #include <string.h>
  26.  
  27. #define INCL_DEV
  28. #define INCL_DOSPROCESS
  29. #define INCL_GPILCIDS
  30. #define INCL_GPIPRIMITIVES
  31. #define INCL_WINBUTTONS
  32. #define INCL_WINDIALOGS
  33. #define INCL_WINERRORS
  34. #define INCL_WINFRAMEMGR
  35. #define INCL_WINHELP
  36. #define INCL_WINMESSAGEMGR
  37. #define INCL_WINMENUS
  38. #define INCL_WINMLE
  39. #define INCL_WINPOINTERS
  40. #define INCL_WINRECTANGLES
  41. #define INCL_WINSHELLDATA
  42. #define INCL_WINSYS
  43. #define INCL_WINWINDOWMGR
  44. #include <os2.h>
  45.  
  46. #include "pmenv.h"
  47. #include "help.h"
  48. #include "dlgsup.h"
  49. #include "printsup.h"
  50.  
  51. typedef struct _PRINTTHREADDATA   /* ptdata */
  52. {
  53.     HWND        hwndDlg;
  54.     PBYTE       pabBufAddr;
  55.     PBYTE       pabBufRetAddr;
  56.     SHORT       PrinterType;
  57.     SHORT       MarginTop;
  58.     SHORT       MarginLeft;
  59. }
  60.     PRINTTHREADDATA;
  61. typedef PRINTTHREADDATA *PPRINTTHREADDATA;
  62.  
  63.  
  64. #define MLE_BUFSIZE 2000
  65.  
  66. #define WMUSER_PRINTFINISHED    WM_USER + 0
  67. #define WMUSER_INITFROMPROFILE  WM_USER + 1
  68.  
  69. #define DEFAULT_PRINTERTYPE     0
  70. #define DEFAULT_MARGINTOP       5
  71. #define DEFAULT_MARGINLEFT      5
  72.  
  73.  
  74. static  HAB     hab;
  75. static  HWND    hwndHelpInstance;
  76.  
  77.  
  78. static MRESULT EXPENTRY
  79. DlgProc (HWND hwnd, USHORT msg, MPARAM mp1, MPARAM mp2);
  80.  
  81. static VOID EnableMarginControls (HWND hwnd, BOOL fEnable);
  82.  
  83. static VOID UpdatePrintMsg (HWND hwnd, USHORT cPrintThreadsRunning);
  84.  
  85. static VOID LaunchPrintThread (HWND hwnd, PBYTE pabBufAddr,
  86.     PBYTE pabBufRetAddr, PUSHORT pcPrintThreadsRunning,
  87.     SHORT PrinterType, SHORT MarginTop, SHORT MarginLeft);
  88.  
  89. static VOID PrintEnvelopeThread (PPRINTTHREADDATA pptdata);
  90.  
  91.  
  92.  
  93. /* ----------------------------------------------------------------- */
  94.  
  95. VOID main (VOID)
  96. {
  97.     HMQ     hmq;
  98.     QMSG    qmsg;
  99.     HWND    hwndDlg;
  100.  
  101.     hab = WinInitialize (0);
  102.     hmq = WinCreateMsgQueue (hab, DEFAULT_QUEUE_SIZE);
  103.  
  104.     hwndDlg = WinLoadDlg (HWND_DESKTOP, HWND_DESKTOP,
  105.         DlgProc, 0, DID_DLG, 0);
  106.  
  107.     hwndHelpInstance = InitializeHelp (hab, hwndDlg, DID_DLG,
  108.         "PMENV.HLP", "Print Envelope Help Window");
  109.  
  110.     while (WinGetMsg (hab, &qmsg, 0, 0, 0))
  111.         WinDispatchMsg (hab, &qmsg);
  112.  
  113.     if (hwndHelpInstance)
  114.     WinDestroyHelpInstance (hwndHelpInstance);
  115.  
  116.     WinDestroyMsgQueue (hmq);
  117.     WinTerminate (hab);
  118. }
  119.  
  120.  
  121.  
  122. /* ----------------------------------------------------------------- */
  123.  
  124. static MRESULT EXPENTRY
  125. DlgProc (HWND hwnd, USHORT msg, MPARAM mp1, MPARAM mp2)
  126. {
  127.     static  PBYTE   pabBufAddr;             /* Address buffer               */
  128.     static  PBYTE   pabBufRetAddr;          /* Return address buffer        */
  129.     ULONG   cbData;                         /* Data length                  */
  130.     static  HWND    hwndSysMenu;            /* Sys menu pull-down handle    */
  131.     static  USHORT  cPrintThreadsRunning;   /* Number of print threads      */
  132.     static  SHORT   PrinterType;            /* Printer type                 */
  133.     static  SHORT   MarginTop;              /* Top margin                   */
  134.     static  SHORT   MarginLeft;             /* Left margin                  */
  135.  
  136.     switch (msg)
  137.     {
  138.         case WM_INITDLG:
  139.         {
  140.             HWND    hwndStamp;              /* Stamp window handle          */
  141.             RECTL   rclStamp;               /* Stamp size                   */
  142.             SWP     swpEnvelope;            /* Envelope position and size   */
  143.             MENUITEM miTemp;                /* Menu item template           */
  144.  
  145.  
  146.             cPrintThreadsRunning = 0;
  147.  
  148.  
  149.             /* Make cosmetic changes to dialog box */
  150.  
  151.             CenterDlgBox (hwnd);
  152.             SetSystemMenu (hwnd);
  153.  
  154.  
  155.             /* Get system menu pull-down handle */
  156.  
  157.             hwndSysMenu = WinWindowFromID (hwnd, FID_SYSMENU );
  158.             WinSendMsg( hwndSysMenu, MM_QUERYITEM,
  159.                         MPFROM2SHORT( SC_SYSMENU, FALSE ),
  160.                         MPFROMP( (PSZ)&miTemp ));
  161.             hwndSysMenu = miTemp.hwndSubMenu;
  162.  
  163.  
  164.             /* Place stamp in upper right corner of envelope */
  165.  
  166.             WinQueryWindowRect (hwndStamp = WinWindowFromID
  167.                 (hwnd, DID_STAMP), &rclStamp);
  168.             WinQueryWindowPos (WinWindowFromID
  169.                 (hwnd, DID_ENVELOPE), &swpEnvelope);
  170.  
  171.             WinSetWindowPos (hwndStamp, 0,
  172.                 (SHORT) (swpEnvelope.x +
  173.                     swpEnvelope.cx - (rclStamp.xRight * 11 / 10)),
  174.                 (SHORT) (swpEnvelope.y +
  175.                     swpEnvelope.cy - (rclStamp.yTop * 11 / 10)),
  176.                 0, 0, SWP_MOVE);
  177.  
  178.  
  179.             /* Allocate MLE buffers */
  180.  
  181.             pabBufAddr    = halloc (MLE_BUFSIZE, 1);
  182.             pabBufRetAddr = halloc (MLE_BUFSIZE, 1);
  183.  
  184.             WinSendDlgItemMsg (hwnd, DID_ADDR, MLM_SETTEXTLIMIT,
  185.                 MPFROMLONG ((LONG) MLE_BUFSIZE - 1), 0);
  186.             WinSendDlgItemMsg (hwnd, DID_RETURN_ADDR, MLM_SETTEXTLIMIT,
  187.                 MPFROMLONG ((LONG) MLE_BUFSIZE - 1), 0);
  188.  
  189.  
  190.             /* Initialize controls from user profile */
  191.  
  192.             WinSendMsg (hwnd, WMUSER_INITFROMPROFILE, 0, 0);
  193.  
  194.             return 0;
  195.         }
  196.  
  197.  
  198.         case WMUSER_INITFROMPROFILE:
  199.             /* Retrieve saved data from user profile */
  200.  
  201.             cbData = MLE_BUFSIZE - 2;
  202.             pabBufAddr [0]      = 0;
  203.             pabBufAddr [cbData] = 0;
  204.  
  205.             PrfQueryProfileData (HINI_USERPROFILE,
  206.                 "PMHPENV", "Address", pabBufAddr, &cbData);
  207.             WinSetDlgItemText (hwnd, DID_ADDR, pabBufAddr);
  208.  
  209.             cbData = MLE_BUFSIZE - 2;
  210.             pabBufRetAddr [0]      = 0;
  211.             pabBufRetAddr [cbData] = 0;
  212.  
  213.             PrfQueryProfileData (HINI_USERPROFILE, "PMHPENV",
  214.                 "ReturnAddress", pabBufRetAddr, &cbData);
  215.             WinSetDlgItemText (hwnd,
  216.                 DID_RETURN_ADDR, pabBufRetAddr);
  217.  
  218.             PrinterType = DEFAULT_PRINTERTYPE;
  219.             cbData = sizeof (SHORT);
  220.             PrfQueryProfileData (HINI_USERPROFILE,
  221.                 "PMHPENV", "PrinterType", &PrinterType, &cbData);
  222.  
  223.             WinSendDlgItemMsg (hwnd, PrinterType ?
  224.                 DID_PRINTER_HP : DID_PRINTER_GENERIC,
  225.                 BM_SETCHECK, MPFROMSHORT (1), 0);
  226.  
  227.             EnableMarginControls (hwnd, ! PrinterType);
  228.  
  229.             MarginTop = DEFAULT_MARGINTOP;
  230.             cbData = sizeof (SHORT);
  231.             PrfQueryProfileData (HINI_USERPROFILE,
  232.                 "PMHPENV", "MarginTop", &MarginTop, &cbData);
  233.             WinSetDlgItemShort (hwnd, DID_MARGIN_TOP,
  234.                 MarginTop, TRUE);
  235.  
  236.             MarginLeft = DEFAULT_MARGINLEFT;
  237.             cbData = sizeof (SHORT);
  238.             PrfQueryProfileData (HINI_USERPROFILE,
  239.                 "PMHPENV", "MarginLeft", &MarginLeft, &cbData);
  240.             WinSetDlgItemShort (hwnd, DID_MARGIN_LEFT,
  241.                 MarginLeft, TRUE);
  242.             break;
  243.  
  244.  
  245.         case WM_COMMAND:
  246.             switch (SHORT1FROMMP (mp1))
  247.             {
  248.                 case DID_SAVE:
  249.  
  250.                     /* Save address in profile */
  251.  
  252.                     WinQueryDlgItemText (hwnd, DID_ADDR, MLE_BUFSIZE,
  253.                         pabBufAddr);
  254.  
  255.                     PrfWriteProfileData (HINI_USERPROFILE,
  256.                         "PMHPENV", "Address", pabBufAddr,
  257.                         (ULONG) strlen (pabBufAddr));
  258.  
  259.                     /* Save return address in profile */
  260.  
  261.                     WinQueryDlgItemText (hwnd, DID_RETURN_ADDR,
  262.                         MLE_BUFSIZE, pabBufRetAddr);
  263.  
  264.                     PrfWriteProfileData (HINI_USERPROFILE, "PMHPENV",
  265.                         "ReturnAddress", pabBufRetAddr,
  266.                         (ULONG) strlen (pabBufRetAddr));
  267.  
  268.                     /* Save printer and margin info in profile */
  269.  
  270.                     PrinterType = SHORT1FROMMR (WinSendDlgItemMsg
  271.                        (hwnd, DID_PRINTER_HP,
  272.                         BM_QUERYCHECK, 0, 0));
  273.                     WinQueryDlgItemShort (hwnd, DID_MARGIN_TOP,
  274.                         &MarginTop, TRUE);
  275.                     WinQueryDlgItemShort (hwnd, DID_MARGIN_LEFT,
  276.                         &MarginLeft, TRUE);
  277.  
  278.                     cbData = sizeof (SHORT);
  279.                     PrfWriteProfileData (HINI_USERPROFILE,
  280.                         "PMHPENV", "PrinterType", &PrinterType, cbData);
  281.  
  282.                     PrfWriteProfileData (HINI_USERPROFILE,
  283.                         "PMHPENV", "MarginTop", &MarginTop, cbData);
  284.  
  285.                     PrfWriteProfileData (HINI_USERPROFILE,
  286.                         "PMHPENV", "MarginLeft", &MarginLeft, cbData);
  287.  
  288.  
  289.                     break;
  290.  
  291.  
  292.                 case DID_DEFAULTS:
  293.                     PrfWriteProfileData (HINI_USERPROFILE,
  294.                         "PMHPENV", 0, 0, 0);
  295.                     WinSendMsg (hwnd, WMUSER_INITFROMPROFILE, 0, 0);
  296.                     break;
  297.  
  298.  
  299.                 case DID_PRINT:
  300.                     PrinterType = SHORT1FROMMR (WinSendDlgItemMsg
  301.                        (hwnd, DID_PRINTER_HP,
  302.                         BM_QUERYCHECK, 0, 0));
  303.                     WinQueryDlgItemShort (hwnd, DID_MARGIN_TOP,
  304.                         &MarginTop, TRUE);
  305.                     WinQueryDlgItemShort (hwnd, DID_MARGIN_LEFT,
  306.                         &MarginLeft, TRUE);
  307.  
  308.                     LaunchPrintThread (hwnd, pabBufAddr,
  309.                         pabBufRetAddr, &cPrintThreadsRunning,
  310.                         PrinterType, MarginTop, MarginLeft);
  311.                     break;
  312.  
  313.  
  314.                 case DID_CANCEL:
  315.                     WinPostMsg (hwnd, WM_CLOSE, 0L, 0L);
  316.                     break;
  317.             }
  318.  
  319.             break;
  320.  
  321.  
  322.         case WM_CONTROL:
  323.             switch (SHORT2FROMMP (mp1))
  324.             {
  325.                 case BN_CLICKED:
  326.                     switch (SHORT1FROMMP (mp1))
  327.                     {
  328.                         case DID_PRINTER_HP:
  329.                             EnableMarginControls (hwnd, FALSE);
  330.                             break;
  331.  
  332.                         case DID_PRINTER_GENERIC:
  333.                             EnableMarginControls (hwnd, TRUE);
  334.                             break;
  335.                     }
  336.  
  337.                     break;
  338.             }
  339.  
  340.             break;
  341.  
  342.  
  343.         case WM_CLOSE:
  344.         {
  345.             BOOL    fClose;
  346.  
  347.             if (cPrintThreadsRunning)
  348.                 fClose = WinMessageBox (HWND_DESKTOP, hwnd,
  349.                     "Printing is under way.  Do you want to "
  350.                     "exit anyway?", "Printing Under Way", 1,
  351.                     MB_YESNO | MB_ICONQUESTION | MB_MOVEABLE)
  352.                     == MBID_YES;
  353.             else
  354.                 fClose = TRUE;
  355.  
  356.             if (fClose)
  357.             {
  358.                 WinPostMsg (0, WM_QUIT, 0L, 0L);
  359.                 WinDestroyWindow (hwnd);
  360.                 hfree (pabBufAddr);
  361.                 hfree (pabBufRetAddr);
  362.             }
  363.             break;
  364.         }
  365.  
  366.  
  367.         case HM_ERROR:
  368.             return ProcessHmMessages (hwndHelpInstance,
  369.                 msg, mp1, mp2);
  370.  
  371.  
  372.         case WMUSER_PRINTFINISHED:
  373.             UpdatePrintMsg (hwnd, --cPrintThreadsRunning);
  374.             break;
  375.  
  376.  
  377.         default:
  378.             return WinDefDlgProc (hwnd, msg, mp1, mp2);
  379.     }
  380.  
  381.     return (MRESULT) 0;
  382. }
  383.  
  384.  
  385.  
  386. /* ----------------------------------------------------------------- */
  387.  
  388. static VOID EnableMarginControls (HWND hwnd, BOOL fEnable)
  389. {
  390.     /*
  391.      *  Enable or disable margin setting controls.  They are not
  392.      *  used when commanding an HP LaserJet.
  393.      */
  394.  
  395.     WinEnableWindow (WinWindowFromID
  396.         (hwnd, DID_MARGIN_TOP), fEnable);
  397.     WinEnableWindow (WinWindowFromID
  398.         (hwnd, DID_MARGIN_LEFT), fEnable);
  399.     WinEnableWindow (WinWindowFromID
  400.         (hwnd, DID_MARGIN_TOP_LBL), fEnable);
  401.     WinEnableWindow (WinWindowFromID
  402.         (hwnd, DID_MARGIN_LEFT_LBL), fEnable);
  403.     WinEnableWindow (WinWindowFromID
  404.         (hwnd, DID_MARGIN_LBL), fEnable);
  405. }
  406.  
  407.  
  408.  
  409. /* ----------------------------------------------------------------- */
  410.  
  411. static VOID LaunchPrintThread (HWND hwnd, PBYTE pabBufAddr,
  412.     PBYTE pabBufRetAddr, PUSHORT pcPrintThreadsRunning,
  413.     SHORT PrinterType, SHORT MarginTop, SHORT MarginLeft)
  414. {
  415.     /*
  416.      *  Create a thread to queue an envelope for printing.
  417.      */
  418.  
  419.     PPRINTTHREADDATA     pptdata;
  420.  
  421.     WinEnableWindow (WinWindowFromID (hwnd, DID_PRINT), FALSE);
  422.  
  423.     WinSetPointer (HWND_DESKTOP,
  424.         WinQuerySysPointer (HWND_DESKTOP,
  425.         SPTR_WAIT, 0));
  426.  
  427.  
  428.     /* Get address data */
  429.  
  430.     WinQueryDlgItemText (hwnd, DID_ADDR,
  431.         MLE_BUFSIZE, pabBufAddr);
  432.     WinQueryDlgItemText (hwnd, DID_RETURN_ADDR,
  433.         MLE_BUFSIZE, pabBufRetAddr);
  434.  
  435.     pptdata = halloc (1L, sizeof *pptdata);
  436.     pptdata->hwndDlg        = hwnd;
  437.     pptdata->pabBufAddr     = strdup (pabBufAddr);
  438.     pptdata->pabBufRetAddr  = strdup (pabBufRetAddr);
  439.     pptdata->PrinterType    = PrinterType;
  440.     pptdata->MarginTop      = MarginTop;
  441.     pptdata->MarginLeft     = MarginLeft;
  442.  
  443.  
  444.     /* Launch the thread */
  445.  
  446.     if (_beginthread (PrintEnvelopeThread,
  447.         0, 8192, pptdata) == -1)
  448.         WinMessageBox (HWND_DESKTOP, hwnd,
  449.             "Print Envelopes can not create "
  450.             "Print Thread", "Print Envelopes Error",
  451.             1, MB_MOVEABLE | MB_OK | MB_ICONASTERISK);
  452.     else
  453.         UpdatePrintMsg (hwnd, ++*pcPrintThreadsRunning);
  454.  
  455.     WinSetPointer (HWND_DESKTOP,
  456.         WinQuerySysPointer (HWND_DESKTOP, SPTR_ARROW, 0));
  457.  
  458.     WinEnableWindow (WinWindowFromID (hwnd, DID_PRINT), TRUE);
  459. }
  460.  
  461.  
  462.  
  463. /* ----------------------------------------------------------------- */
  464.  
  465. static VOID UpdatePrintMsg (HWND hwnd, USHORT cPrintThreadsRunning)
  466. {
  467.     /*
  468.      *  Update the print status message which indicates how many
  469.      *  print threads are running.
  470.      */
  471.  
  472.     CHAR    szMsg [40];
  473.  
  474.     if (cPrintThreadsRunning)
  475.         sprintf (szMsg, "Envelopes printing: %u",
  476.             cPrintThreadsRunning);
  477.     else
  478.         *szMsg = 0;
  479.  
  480.     WinSetDlgItemText (hwnd, DID_PRINT_MSG, szMsg);
  481. }
  482.  
  483.  
  484.  
  485. /* ----------------------------------------------------------------- */
  486.  
  487. static VOID PrintEnvelopeThread (PPRINTTHREADDATA pptdata)
  488. {
  489.     /*
  490.      *  Queue an envelope for printing.
  491.      */
  492.  
  493.     HDC     hdcPrint;
  494.     USHORT  usJobId;
  495.     CHAR    szPrintTitle [100];
  496.     PBYTE   pchCR;
  497.     HAB     habPrint;
  498.     HMQ     hmqPrint;
  499.     SIZEL   sizl;
  500.     HPS     hpsPrint;
  501.     POINTL  ptl;
  502.     LONG    cyPage;
  503.     LONG    cxPage;
  504.     FONTMETRICS fm;
  505.  
  506.  
  507.     habPrint = WinInitialize (0);
  508.     hmqPrint = WinCreateMsgQueue (habPrint, DEFAULT_QUEUE_SIZE);
  509.  
  510.  
  511.     /* Set priority lower than main thread */
  512.  
  513.     DosSetPrty (PRTYS_THREAD, PRTYC_NOCHANGE, -1, 0);
  514.  
  515.  
  516.     /* Make print spooler document title from envelope address */
  517.  
  518.     if ((pchCR = strchr (pptdata->pabBufAddr, '\r')) != 0)
  519.     {
  520.         USHORT  cbFirstLine;
  521.         USHORT  cbTitlePart1;
  522.         USHORT  cbMaxConcat;
  523.  
  524.         memset (szPrintTitle, 0xff, sizeof szPrintTitle);
  525.         strcpy (szPrintTitle, "Env. - ");
  526.         cbTitlePart1 = strlen (szPrintTitle);
  527.         cbFirstLine = pchCR - pptdata->pabBufAddr;
  528.         cbMaxConcat = min (cbFirstLine,
  529.             sizeof szPrintTitle - cbTitlePart1 - 1);
  530.         strncat (szPrintTitle, pptdata->pabBufAddr, cbMaxConcat);
  531.     }
  532.     else
  533.         strcpy (szPrintTitle, "Envelope");
  534.  
  535.  
  536.     /* Perform document initialization */
  537.  
  538.     OpenDefaultPrinterDC (hab, &hdcPrint,
  539.         pptdata->PrinterType ? "PM_Q_RAW" : "PM_Q_STD");
  540.  
  541.     DevQueryCaps (hdcPrint, CAPS_HEIGHT, 1L, &cyPage);
  542.     DevQueryCaps (hdcPrint, CAPS_WIDTH,  1L, &cxPage);
  543.  
  544.     DevEscape (hdcPrint, DEVESC_STARTDOC,
  545.         (LONG) strlen (szPrintTitle), szPrintTitle, 0L, 0);
  546.  
  547.  
  548.     if (pptdata->PrinterType)   /* HP Printer - dump raw data */
  549.     {
  550.         /* Print return address */
  551.  
  552.         PrintString( hdcPrint,
  553.             "\x01b" "E\x1b&l1O\x1b&l3H\x1b&l15E" );
  554.         PrintString( hdcPrint, "\x1b&a1r&a15L" );
  555.         PrintString( hdcPrint, pptdata->pabBufRetAddr );
  556.  
  557.  
  558.         /* Print address */
  559.  
  560.         PrintString( hdcPrint, "\x1b&a11R" );  /* Line position */
  561.         PrintString( hdcPrint, "\x1b&a58L" );  /* Column position */
  562.         PrintString( hdcPrint, pptdata->pabBufAddr );
  563.         PrintString( hdcPrint, "\f\x01b" "E" );
  564.     }
  565.     else                        /* Generic Printer - use GPI */
  566.     {
  567.         sizl.cx = sizl.cy = 0L;
  568.         hpsPrint = GpiCreatePS( habPrint, hdcPrint, &sizl,
  569.             PU_PELS | GPIF_DEFAULT | GPIT_NORMAL | GPIA_ASSOC );
  570.  
  571.         GpiQueryFontMetrics (hpsPrint, sizeof fm, &fm);
  572.  
  573.         ptl.x = pptdata->MarginLeft * fm.lAveCharWidth;
  574.         ptl.y = cyPage - pptdata->MarginTop * fm.lMaxBaselineExt;
  575.         PrintLinesAt (hpsPrint, ptl,
  576.             pptdata->pabBufRetAddr, fm.lMaxBaselineExt);
  577.  
  578.         ptl.x = cxPage / 2;
  579.         ptl.y = cyPage - (pptdata->MarginTop + 10)
  580.             * fm.lMaxBaselineExt;
  581.         PrintLinesAt (hpsPrint, ptl,
  582.             pptdata->pabBufAddr, fm.lMaxBaselineExt);
  583.  
  584.         GpiAssociate( hpsPrint, 0 );
  585.         GpiDestroyPS( hpsPrint );
  586.     }
  587.  
  588.  
  589.     /* Perform document and thread termination */
  590.  
  591.     DevEscape (hdcPrint, DEVESC_ENDDOC, 0L, 0, 0L,
  592.         (PBYTE) &usJobId);
  593.  
  594.     DevCloseDC (hdcPrint);
  595.  
  596.     WinDestroyMsgQueue (hmqPrint);
  597.     WinTerminate (habPrint);
  598.  
  599.  
  600.     /* Notify main thread that this thread is done */
  601.  
  602.     WinPostMsg (pptdata->hwndDlg, WMUSER_PRINTFINISHED, 0, 0);
  603.  
  604.  
  605.     /* Free per-thread-instance address buffers */
  606.  
  607.     free (pptdata->pabBufAddr);
  608.     free (pptdata->pabBufRetAddr);
  609.  
  610.  
  611.     /* Free other per-thread-instance data */
  612.  
  613.     hfree (pptdata);
  614. }
  615.